import 'dart:convert';
import 'i_store.dart';
import 'package:shared_preferences/shared_preferences.dart';

class SpStore extends IStore {
  late SharedPreferences _prefs;

  @override
  Future<void> init() async {
    _prefs = await SharedPreferences.getInstance();
  }

  String _getNameKey(String key, {String? name}) {
    return (name == null || name.isEmpty) ? key : "$name.$key";
  }

  @override
  String getString(String key, {String def = "", String? name}) {
    return getAny(key, String, name: name) ?? def;
  }

  @override
  bool setString(String key, String value, {String? name}) {
    return setAny(key, value, name: name);
  }

  @override
  int getInt(String key, {int def = 0, String? name}) {
    return getAny(key, int, name: name) ?? def;
  }

  @override
  bool setInt(String key, int value, {String? name}) {
    return setAny(key, value, name: name);
  }

  @override
  double getDouble(String key, {double def = 0, String? name}) {
    return getAny(key, double, name: name) ?? def;
  }

  @override
  bool setDouble(String key, double value, {String? name}) {
    return setAny(key, value, name: name);
  }

  bool getBool(String key, {bool def = false, String? name}) {
    return getAny(key, bool, name: name) ?? def;
  }

  @override
  bool setBool(String key, bool value, {String? name}) {
    return setAny(key, value, name: name);
  }

  @override
  List<String> getStringList(String key, {List<String> def = const [], String? name}) {
    return getAny(key, List<String>, name: name) ?? def;
  }

  @override
  bool setStringList(String key, List<String> value, {String? name}) {
    return setAny(key, value, name: name);
  }

  @override
  Map getMap(String key, {Map def = const {}, String? name}) {
    return getAny(key, Map, name: name) ?? def;
  }

  @override
  bool setMap(String key, Map value, {String? name}) {
    return setAny(key, value, name: name);
  }

  dynamic getAny(String key, Type type, {String? name}) {
    final keyName = _getNameKey(key, name: name);
    if (type == String) {
      return _prefs.getString(keyName);
    } else if (type == int) {
      return _prefs.getInt(keyName);
    } else if (type == double) {
      return _prefs.getDouble(keyName);
    } else if (type == bool) {
      return _prefs.getBool(keyName);
    } else if (type == List<String>) {
      return _prefs.getStringList(keyName);
    } else {
      return _getJson(key, name: name);
    }
  }

  /// 批量设置键值对
  bool setAny(String key, dynamic value, {String? name}) {
    try {
      final keyName = _getNameKey(key, name: name);
      if (value is String) {
        _prefs.setString(keyName, value);
        return true;
      } else if (value is int) {
        _prefs.setInt(keyName, value);
        return true;
      } else if (value is double) {
        _prefs.setDouble(keyName, value);
        return true;
      } else if (value is bool) {
        _prefs.setBool(keyName, value);
        return true;
      } else if (value is List<String>) {
        _prefs.setStringList(keyName, value);
        return true;
      } else {
        // 对于所有其他类型，尝试将它们转换为 JSON 字符串
        try {
          final jsonString = jsonEncode(value);
          _prefs.setString(keyName, jsonString);
          return true;
        } catch (e) {
          throw UnsupportedError('Failed to convert to JSON: ${value.runtimeType}');
        }
      }
    } catch (e) {
      throw UnsupportedError('Failed to mmkv  ${value.runtimeType},$e');
    }
  }

  @override
  bool contains(String key, {String? name}) {
    return _prefs.containsKey(_getNameKey(key, name: name));
  }

  @override
  bool remove(String key, {String? name}) {
    _prefs.remove(_getNameKey(key, name: name));
    return true;
  }

  @override
  void clear({String? name}) {
    if (name != null && name.isNotEmpty) {
      _prefs.getKeys().forEach((key) {
        if (key.startsWith("$name.")) {
          _prefs.remove(key);
        }
      });
    } else {
      _prefs.clear();
    }
  }

//获取json形式
  dynamic _getJson(String key, {String? name}) {
    if (contains(key, name: name)) {
      final value = getString(key);
      try {
        return jsonDecode(value);
      } catch (e) {
        return null;
      }
    } else {
      return null;
    }
  }
}
